package main

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
)

func main() {
	fmt.Println("使用json序列化与反序列化：")
	jsonMarshal()

	fmt.Println("自定义序列化:")
	DemoMarshal()
}

// 使用json协议序列化与反序列化
func jsonMarshal() {
	t := Test{
		F1: 0x1234,
		F2: 0x4567,
		F3: 12,
	}

	// 序列化
	bs, err := json.Marshal(&t)
	if nil != err {
		fmt.Println("序列化错误：", err)
		return
	}
	fmt.Println("[ test -> []byte ]:", bs)

	// 反序列化
	ts := Test{}
	err = json.Unmarshal(bs, &ts)
	if nil != err {
		fmt.Println("反序列化错误：", err)
		return
	}
	fmt.Println("[ []byte -> test ]:", ts)

}

type Test struct {
	F1 uint64
	F2 uint32
	F3 byte
}

/*
Test 内存占用只有 16 个字节，但是 json 序列化完之后占用 30 个字节。
如果一定要按照16个字节，只能自定义序列化，也就是自己准备协议——自定义针对某个结构体的序列化
*/

func (t *Test) Marshal() ([]byte, error) {
	// 将各个属性依次转化为[]byte ，并填充返回
	buf := make([]byte, 16)

	// 序列化
	binary.BigEndian.PutUint64(buf[0:8], t.F1)  // 8字节
	binary.BigEndian.PutUint32(buf[8:12], t.F2) // 4字节
	buf[12] = t.F3                              // 1字节
	// 使用大端序，因为网络传输、磁盘存储一般都是大端序。

	return buf, nil
}

func (t *Test) Unmarshal(buf []byte) error {
	if len(buf) == 0 {
		return fmt.Errorf("没有字节数据需要处理")
	}

	// 反序列化
	t.F1 = binary.BigEndian.Uint64(buf[0:8])
	t.F2 = binary.BigEndian.Uint32(buf[8:12])
	t.F3 = buf[12]

	return nil
}

func DemoMarshal() {
	t := Test{
		F1: 0x1234,
		F2: 0x4567,
		F3: 12,
	}

	// 序列化
	bs, err := t.Marshal()
	if nil != err {
		fmt.Println("序列化失败：", err)
		return
	}
	fmt.Println("[ test -> []byte ]:", bs)

	// 反序列化
	ts := Test{}
	err = ts.Unmarshal(bs)
	if nil != err {
		fmt.Println("反序列化失败: ", err)
		return
	}
	fmt.Println("[ []byte -> test ]:", ts)
}
